package com.tools.s7.photo;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;

import com.tools.s7.utils.DateUtils;
import com.tools.s7.utils.FileUtils;

import java.io.File;
import java.io.IOException;

import top.zibin.luban.CompressionPredicate;
import top.zibin.luban.Luban;
import top.zibin.luban.OnCompressListener;

/**
 * 图片选取
 */
public class PhotoUtils {

    // 图片--拍照
    public static final int SELECT_FROM_CAMERA = 0x0011;
    // 图片--相册选取
    public static final int SELECT_FROM_PHOTO = 0x0012;
    // 图片--裁剪
    public static final int SELECT_FROM_CROP = 0x0013;

    private OnPhotoListener mListener;
    private String provider;

    /**
     * 文件夹路径
     */
    private String filePath = Environment.getExternalStorageDirectory().getPath();

    /**
     * 拍照后照片存储路径
     */
    private Uri pathUri;
    private File pathFile;

    /**
     * 裁剪后照片存储路径
     */
    private Uri cropUri;

    /**
     * 是否裁剪
     */
    private boolean isCrop = false;

    /**
     * 裁剪尺寸
     */
    private int cropX = 480;
    private int cropY = 480;

    /**
     * 裁剪比例
     */
    private int aspectX = 1;
    private int aspectY = 1;

    public PhotoUtils(String provider) {
        this.provider = provider;
    }

    public PhotoUtils(String provider, OnPhotoListener mListener) {
        this.provider = provider;
        this.mListener = mListener;
    }

    /**
     * 设置文件夹路径
     * @param filePath
     */
    public PhotoUtils setFilePath(String filePath) {
        this.filePath = filePath;
        return this;
    }

    /**
     * 创建文件夹路径
     * @param name
     */
    public PhotoUtils addFileName(String name) {
        filePath = filePath + "/" + name;
        return this;
    }

    /**
     * 设置是否裁剪
     * @param isCrop 是否裁剪
     */
    public PhotoUtils setCrop(boolean isCrop) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            this.isCrop = isCrop;
        }
        this.isCrop = false;
        return this;
    }

    /**
     * 裁剪后照片存储路径
     * @return
     */
    private Uri getCropUri() {
        File cropFile = new File(filePath, getPhotoName());
        // 对照片的更换设置
        try {
            // 如果上一次的照片存在，就删除
            if (cropFile.exists()) {
                cropFile.delete();
            }
            // 创建一个新的文件
            cropFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Uri cropUri = Uri.fromFile(cropFile);
        return cropUri;
    }

    /**
     * 裁剪尺寸(图片被裁减的宽高)
     * @param width 剪裁图片的宽度
     * @param height 剪裁图片高度
     */
    public PhotoUtils setCropSize(int width, int height) {
        this.cropX = width;
        this.cropY = height;
        return this;
    }

    /**
     * 裁剪比例
     * @param aspectX X方向的比例
     * @param aspectY Y方向的比例
     */
    public PhotoUtils setCropAspect(int aspectX, int aspectY) {
        this.aspectX = aspectX;
        this.aspectY = aspectY;
        return this;
    }

    /**
     * 调用系统相机拍照
     * @param activity 当前activity
     * */
    public void onCamera(Activity activity) {
        onCamera(activity, getPhotoName());
    }

    /**
     * 调用系统相机拍照
     * @param activity 当前activity
     * @param name 保存的名字
     * */
    public void onCamera(Activity activity, String name) {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 创建一个File对象，用于保存摄像头拍下的图片
        pathFile = new File(filePath, name);
        // 对照片的更换设置
        try {
            // 如果上一次的照片存在，就删除
            if (pathFile.exists()) {
                pathFile.delete();
            }
            // 创建一个新的文件
            pathFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (Build.VERSION.SDK_INT < 24) {
            pathUri = Uri.fromFile(pathFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, pathUri);
        } else {
            pathUri = FileProvider.getUriForFile(activity, provider, pathFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, pathUri);
        }
        activity.startActivityForResult(intent, SELECT_FROM_CAMERA);
        if (mListener != null) {
            mListener.onPhotoCallback(0, "开始拍照");
        }
    }


    /**
     * 相册选取
     * @param activity 当前activity
     */
    public void onPhoto(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        activity.startActivityForResult(intent, SELECT_FROM_PHOTO);
        if (mListener != null) {
            mListener.onPhotoCallback(0, "开始选择照片");
        }
    }

    /**
     * 裁剪
     *  @param activity 当前activity
     *  @param orgUri 剪裁原图的Uri
     */
    public void cropImage(Activity activity, Uri orgUri) {
        cropUri = getCropUri();
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intent.setDataAndType(orgUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", aspectX);
        intent.putExtra("aspectY", aspectY);
        intent.putExtra("outputX", cropX);
        intent.putExtra("outputY", cropY);
        intent.putExtra("scale", true);
        //将剪切的图片保存到目标Uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", false);
        intent.putExtra("scaleUpIfNeeded", true);
        activity.startActivityForResult(intent, SELECT_FROM_CROP);
        if (mListener != null) {
            mListener.onPhotoCallback(0, "开始裁剪照片");
        }
    }

    /**
     * 图片压缩
     * @param context 上下文对象
     * @param path Photo 地址
     */
    private void onCompress(Context context, String path) {
        if (!FileUtils.fileIsExists(path)) {
            if (mListener != null) {
                mListener.onPhotoCallback(-1, "没有找到SD卡");
            }
            return;
        }
        Luban.with(context)
                .load(new File(path))
                .ignoreBy(100)
                .setTargetDir(filePath)
                .filter(new CompressionPredicate() {
                    @Override
                    public boolean apply(String path) {
                        return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif"));
                    }
                })
                .setCompressListener(new OnCompressListener() {
                    @Override
                    public void onStart() {
                        if (mListener != null) {
                            mListener.onPhotoCallback(2, "开始压缩");
                        }
                    }

                    @Override
                    public void onSuccess(File file) {
                        if (mListener != null) {
                            mListener.onPhotoPath(file.getAbsolutePath());
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (mListener != null) {
                            mListener.onPhotoCallback(-1, "压缩失败");
                        }
                    }
                }).launch();
    }

    /**
     * 返回后图片处理
     * @param activity
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK) {
            switch (requestCode) {
                case SELECT_FROM_CAMERA:
                    saveCamera(activity);
                    break;
                case SELECT_FROM_PHOTO:
                    savePhoto(activity, data);
                    break;
                case SELECT_FROM_CROP:
                    saveCrop(activity, data);
                    break;
                default:
                    break;
            }
        } else {
            if (mListener != null) {
                mListener.onPhotoCallback(-1, "放弃选取");
            }
        }
    }

    /**
     * 裁剪返回
     * @param activity
     * @param data
     */
    private void saveCrop(Activity activity, Intent data) {
        if (data == null) {
            if (mListener != null) {
                mListener.onPhotoCallback(-1, "未找到图片");
            }
            return;
        }
        if (data.getData() == null) {
            onCompress(activity, getRealPathFromUri(activity, cropUri));
        } else {
            onCompress(activity, getRealPathFromUri(activity, data.getData()));
        }
    }

    /**
     * 相册选取处理
     * @param activity
     * @param data
     */
    private void savePhoto(Activity activity, Intent data) {
        if (data == null) {
            if (mListener != null) {
                mListener.onPhotoCallback(-1, "未找到图片");
            }
            return;
        }
        if (isCrop) {
            Uri orgUri = Uri.parse(getRealPathFromUri(activity, data.getData()));
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                orgUri = FileProvider.getUriForFile(activity, provider, new File(orgUri.getPath()));
            }
            cropImage(activity, orgUri);
        } else {
            onCompress(activity, getRealPathFromUri(activity, data.getData()));
        }
    }

    /**
     * 拍照结果处理
     * @param activity
     */
    private void saveCamera(Activity activity) {
        if (FileUtils.fileIsExists(pathFile.getPath())) {
            if (isCrop) {
                cropImage(activity, pathUri);
            } else {
                onCompress(activity, pathFile.getPath());
            }
        } else {
            if (mListener != null) {
                mListener.onPhotoCallback(-1, "拍照失败");
            }
        }
    }

    /**
     * 读取uri所在的图片
     * @param uri 图片对应的Uri
     * @param mContext 上下文对象
     * @return 获取图像的Bitmap
     */
    public static Bitmap getBitmapFromUri(Uri uri, Context mContext) {
        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), uri);
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据Uri获取图片的绝对路径
     * @param context 上下文对象
     * @param uri 图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    public static String getRealPathFromUri(Context context, Uri uri) {
        int sdkVersion = Build.VERSION.SDK_INT; if (sdkVersion >= 19) {
            // api >= 19
            return getRealPathFromUriAboveApi19(context, uri);
        } else {
            // api < 19
            return getRealPathFromUriBelowAPI19(context, uri);
        }
    }

    /**
     * 适配api19以下(不包括api19),根据uri获取图片的绝对路径
     * @param context 上下文对象
     * @param uri 图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
        return getDataColumn(context, uri, null, null);
    }
    /**
     * 适配api19及以上,根据uri获取图片的绝对路径
     * @param context 上下文对象
     * @param uri 图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    @SuppressLint("NewApi")
    private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
        String filePath = "";
        if (uri == null) {
            return filePath;
        }
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是document类型的 uri, 则通过document id来进行处理
            String documentId = DocumentsContract.getDocumentId(uri);
            if (isMediaDocument(uri)) {
                // MediaProvider
                // 使用':'分割
                String id = documentId.split(":")[1];
                String selection = MediaStore.Images.Media._ID + "=?";
                String[] selectionArgs = {id};
                filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
            } else if (isDownloadsDocument(uri)) {
                // DownloadsProvider
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                filePath = getDataColumn(context, contentUri, null, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())){
            // 如果是 content 类型的 Uri
            filePath = getDataColumn(context, uri, null, null);
        } else if ("file".equals(uri.getScheme())) {
            // 如果是 file 类型的 Uri,直接获取图片对应的路径
            filePath = uri.getPath();
        }
        return filePath;
    }

    /**
     * 获取数据库表中的 _data 列，即返回Uri对应的文件路径
     * @return
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        String path = null; String[] projection = new String[]{MediaStore.Images.Media.DATA};
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                path = cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            if (cursor != null) {
                cursor.close();
            }
        }
        return path;
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is MediaProvider
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is DownloadsProvider
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * 生成图片名
     */
    public static String getPhotoName() {
        return "PC" + DateUtils.getTimeName() + ".jpg";
    }
}

